﻿using UnityEngine;
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;

// if new data is deployed on server, client could detect this change at the start of game and get latest data.
// configuration file's name is 'dataInfo.json'. Configuration file includes:
// - build Counter: build counter from TeamCity, only version number of all data;
// - data file names: list all files that needed to download if data is changed.
// - MD5: MD5 for each file.
using System.Collections.Generic;
using System;

public class DataSync : MonoBehaviour {

	private const string MarketVersionKey = "MarketVersionKey"; //最近数据更新成功后，存储版本号
	public const string DataUploadKey = "DataUploadKey"; //最近数据更新成功后，存储数据更新upload号

	private const string dataInfoFileName = "dataInfo.json";

	public static int dataVerUpdate = 0;
	public static int dataMin = 0;

	private class FileInfo
	{
		public string file;
		public string md5;
	}

	private class DataInfo {
		public int version;
		public string path;
		public List<FileInfo> fileInfos;
	}

	private DataInfo localDataInfo;
	private bool updateCompleted = false;

	private string dataInfoFileDirectoryInStreamingAssets {
		get {
			return Path.Combine(Application.streamingAssetsPath, "data").Replace('\\', '/').TrimEnd(new char[]{'/'});
		}
	}
	private string dataInfoFilePathInCache {
		get {
			return Path.Combine(Application.persistentDataPath, "gamedata").Replace('\\', '/').TrimEnd(new char[]{'/'});
		}
	}

	string _dataURL;
	private string dataURL {
		get
		{
			return _dataURL;
		}
		set 
		{
			_dataURL = value;
		}
	}

	private static DataSync __inst;
	public static DataSync Instance {
		get {
			return __inst;
		}
	}
	//private class Logger : LoggerSingleton<Logger> {
	//	public Logger() {
	//		SetLoggerName("DataSync");
	//	}
	//}

	private delegate void DownloadDelegate(DataInfo config, string context, string filename, int code);
	public delegate void DataSyncCallback();
	private DataSyncCallback _completedCallback;
	private bool _dataSyncCompleted = false;
	public System.Collections.Generic.Dictionary<System.Type, object> _dataAfterDeserialized = new System.Collections.Generic.Dictionary<System.Type, object>();
	private int _dataLoaded;
	private bool _isUsingSteamingData = false;

	//public delegate void OnProgressError(AppLoadingError errorType);
	//public OnProgressError _onProgressError;

	void Awake() {
		if(__inst != null) {
			//Logger.Error("duplicated DataSync instances exist in scene.");
            Debug.Log( "duplicated DataSync instances exist in scene." );
            return;
		}
		__inst = this;
		
		//dataURL = Path.Combine(Path.Combine(Path.Combine(dataServerAddr, AppInfo.productId), AppInfo.marketVersion), dataVerUpdate.ToString()).Replace('\\', '/').TrimEnd(new char[]{'/'});
	}

	void OnDestroy() {
		if(__inst == this) {
			__inst = null;
		}
	}

	void Update()
	{
		if(_completedCallback != null) {
			if(_dataSyncCompleted) {
				int version = 0;
				
				//FIXME by RCD. dataVerUpdate 干吗用的？　为什么不用datainfo里的version呢
				//Logger.Debug("update data version to " + version);
                Debug.Log( "update data version to " + version );
                //AppInfo.dataUpdateCounter = dataVerUpdate;

                //FIXME，何用？
                //_totalUpdateCount = 1f;
                //_updatedCount = 1f;

                _completedCallback();
				_completedCallback = null;


				#if LOADING_STATICS	
				AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync end", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
				#endif
			}
		}
	}

	public void ClearCache()
	{
		Directory.Delete(dataInfoFilePathInCache, true);

		// save current version
		PlayerPrefs.DeleteKey(MarketVersionKey);
		PlayerPrefs.DeleteKey(DataUploadKey);
		PlayerPrefs.Save();
	}


//    #region bug

//    // 数据更新入口
//    public void StartSync(DataSyncCallback onCompleted)
//	{
//		#if LOADING_STATICS	
//		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync start", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//		#endif

//		Logger.Debug("DataSync Start");

//		_completedCallback = onCompleted;
//		_dataSyncCompleted = false;

//		// 如果是覆盖安装(marketVersion与上次运行不同)，则强制拷贝数据
//		var lastVersion = PlayerPrefs.GetString(MarketVersionKey);
//		var curVersion = AppInfo.marketVersion;
//		bool isForceCopy = lastVersion != curVersion;
//		if (isForceCopy)
//		{
//			AppLogger.Debug("DataSync 覆盖安装，强制拷贝数据");
//		}

//		StartCoroutine(DataSyncCoroutine(isForceCopy));
//	}

//	private bool _copySuccess = false;
//	IEnumerator DataSyncCoroutine(bool isForceCopy = false)
//	{
//		if (isForceCopy)
//		{
//			try
//			{
//				if (Directory.Exists(dataInfoFilePathInCache))
//				{
//					AppLogger.Debug("DataSync 强制拷贝，删除已存在目录");
//					Directory.Delete(dataInfoFilePathInCache, true);

//					//版本号都变了，删除缓存的数据和bundle号
//					PlayerPrefs.SetString(MarketVersionKey, AppInfo.marketVersion);
//					PlayerPrefs.DeleteKey(DataUploadKey);
//					PlayerPrefs.Save();
//				}
//			}
//			catch (Exception ex)
//			{
//				Logger.Error("DataSync 删除已存在目录失败");
//				Logger.Error(ex.StackTrace);
//			}
//		}


//		DataInfo infoInCache = new DataInfo();
//		DataInfo infoInStreamingAssets = new DataInfo();

//		//先从cache目录里面查找文件，如果有，则不用考虑stream目录
//		yield return StartCoroutine(GetDataInfo(dataInfoFilePathInCache, infoInCache));

//		if (infoInCache.version != -1)
//		{
//			// 已拷贝过数据
//			AppLogger.Debug("DataSync 使用缓存数据");
//			_isUsingSteamingData = false;
//			localDataInfo = infoInCache;
//		}
//		else
//		{
//			yield return StartCoroutine(GetDataInfo(dataInfoFileDirectoryInStreamingAssets, infoInStreamingAssets));

//			AppLogger.Debug("DataSync 使用本地数据");
//			_isUsingSteamingData = true;
//			localDataInfo = infoInStreamingAssets;
//		}

//#if LOADING_STATICS	
//		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, Local dataVersion is {2}", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString(), localDataInfo.version);
//#endif
//		VerInfoLogger.Warn("DataSync Local dataVersion is {0}", localDataInfo.version);

//		if (localDataInfo.version == -1)
//		{
//			//两个目录里面都没有datainfo，是本地编辑器版本，跳过后续检测 
//			Logger.Debug("[DataSync] 这是编辑器版本");
//			_dataSyncCompleted = true;
//		}
//		else if(dataVerUpdate == 0) 
//		{
//			// dataVerUpdate 为0，说明公告没有配数据更新，跳过检测

//#if LOADING_STATICS	
//			AppLogger.Error("[LOADING STATICS] [{0}] [{1}] No update available, skip updating", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//#endif
//			Logger.Debug("No update available, skip updating");
//			_dataSyncCompleted = true;
//		}
//		else
//		{
//			//有cache缓存，并且公告里面填写的dateaupdate号和本地的dateupload号相同， 说明可以跳过 
//			if ((!_isUsingSteamingData) && (dataVerUpdate.Equals(PlayerPrefs.GetInt(DataUploadKey))))
//			{
//				Logger.Debug("[DataSync] 有dateupload号，但是本地已经有缓存");
//				_dataSyncCompleted = true;
//			}
//			else
//			{
//				// 获取远端配置的更新版本
//				StartCoroutine(GetDataInfoConfig(0.0f));
//			}
//		}
//	}

//	private IEnumerator CopyDataFile(DataInfo souceInfo)
//	{
//		_copySuccess = false;

//		#if LOADING_STATICS	
//		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] CopyDataFile start", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//		#endif

//		Logger.Debug("DataSync CopyDataFile start");

//		var fileNames = souceInfo.fileInfos;
//		for (int i = 0; i < fileNames.Count; i++)
//		{
//			string fileName = fileNames[i].file;
//			byte[] fileContent = null;
//			DataBytes dataBytes = new DataBytes();
//			yield return StartCoroutine(GetDataBytes(fileName, dataBytes));
//			fileContent = dataBytes.bytes;
			
//			if (fileContent != null)
//			{
//				Logger.Debug("copying " + fileName);
//				try
//				{
//					File.WriteAllBytes(Path.Combine(dataInfoFilePathInCache, fileName).Replace('\\', '/').TrimEnd(new char[]{'/'}), fileContent);
//				}
//				catch (Exception ex)
//				{
//					Logger.Error(ex.StackTrace);
//					HandleUpdateError(AppLoadingError.DISK_FULL);
//					yield break;
//				}
//			}
//			else
//			{
//				Logger.Error("copying " + fileName + " error, content is null");
//			}
//		}

//		DataBytes dataInfo = new DataBytes();
//		yield return StartCoroutine(GetDataBytes(dataInfoFileName, dataInfo));
//		if (dataInfo != null)
//		{
//			Logger.Debug("copying " + dataInfoFileName);
//			try
//			{
//				File.WriteAllBytes(Path.Combine(dataInfoFilePathInCache, dataInfoFileName).Replace('\\', '/').TrimEnd(new char[]{'/'}), dataInfo.bytes);
//			}
//			catch (Exception ex)
//			{
//				Logger.Error(ex.StackTrace);
//				HandleUpdateError(AppLoadingError.DISK_FULL);
//			}
//		}
//		else
//		{
//			Logger.Error("copying " + dataInfoFileName + " error, dataInfo is null");
//		}
		
//		#if LOADING_STATICS	
//		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] CopyDataFile end", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//		#endif

//		Logger.Debug("DataSync CopyDataFile end");

//		_copySuccess = true;
//	}
	
//	//获取到正确的dataInfo.json
//	void RetrieveDataVersionSuccess(string json)
//	{
//		Hashtable table = (Hashtable)TaiJson.jsonDecode(json);
//		// 根据 table.ContainsKey("version") && table.ContainsKey("dataFiles") 来判断返回数据是否正确
//		if(table != null && table.ContainsKey("version") && table.ContainsKey("dataFiles")) {
//			DataInfo info = new DataInfo();
//			GetDataInfo(table, dataInfoFilePathInCache, info);

//			VerInfoLogger.Warn("DataSync Remote dataVersion is {0}", info.version);
//			VerInfoLogger.Warn("DataSync local dataVersion is {0}", localDataInfo.version);

//			#if LOADING_STATICS	
//			AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, Remote dataVersion is {2}", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString(), info.version);
//			AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, local dataVersion is {2}", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString(), localDataInfo.version);
//			#endif
			
//			// 是否需要更新
//			if(info.version != localDataInfo.version) {

//				// 需要更新
//				#if LOADING_STATICS	
//				AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, Versions are diffrent, will downloadData from server", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//				#endif
				
//				// downloading start...
//				if(!Directory.Exists(dataInfoFilePathInCache)) {
//					Directory.CreateDirectory(dataInfoFilePathInCache);
//				}

//				_copySuccess = false;

//				// 是否使用包中数据（缓存中是否有数据文件）
//				if (_isUsingSteamingData)
//				{
//					#if LOADING_STATICS	
//					AppLogger.Error("[LOADING STATICS] [{0}] [{1}] copy data from SteamingAssets before downloadData", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//					#endif
//					// 缓存目录没有文件，从包中拷贝一份，为热更做准备
//					StartCoroutine(CopyDataFile(localDataInfo));
//				}
//				else
//				{
//					// 缓存目录有文件，直接进行热更
//					_copySuccess = true;
//				}

//				StartCoroutine(DownloadDataFromServer(info, json, DownloadDataSuccess, DownloadDataFail));
//			}
//			else {
//				// 不需要更新
//				_dataSyncCompleted = true;
//				#if LOADING_STATICS
//				AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, Versions are the same, skip updating data", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//				#endif
//				Logger.Debug("DataSync Versions are the same, skip updating data");
//			}
//		}
//		else
//		{
//			RetrieveDataVersionFail(CONST_NET.ERRORCODE_HTTP_UNEXPECTED);
//		}
//	}

//	//获取失败dataInfo.json
//	//TODO by RCD，链接不上更新服务器，使用本地数据。需要处理数据不一致的情况。提示玩家重新启动？
//	void RetrieveDataVersionFail(int errorcode,string exception = null,string stackTrace = null) {
//		if(errorcode == CONST_NET.ERRORCODE_HTTP_CONNECTIONTIMEOUT
//		   || errorcode == CONST_NET.ERRORCODE_HTTP_TIMEDOUT) {
			
//			#if LOADING_STATICS
//			AppLogger.Error("[LOADING STATICS] [{0}] [{1}] StartSync, Retrive data version time out, retry!", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//			#endif

//			Logger.Error("DataSync Retrive data version time out, retry!");

//			StartCoroutine(GetDataInfoConfig(0.1f));
//		}
//		else {
//			Logger.Error("Can not connect to data s3 server, use local data." + dataURL);
			
//			#if LOADING_STATICS
//			AppLogger.Error("[LOADING STATICS] [{0}] [{1}] Get Remote dataVersion failed", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
//			#endif
//			Logger.Error("DataSync Get Remote datainfo.json failed, code " + errorcode.ToString());
			
////			_dataSyncCompleted = true;
//			HandleUpdateError(AppLoadingError.DATA_UPDATE_FAILED);
//		}
//	}

//	//get all data succ callback
//	void DownloadDataSuccess(DataInfo config, string context, string filename, int code)
//	{
//		localDataInfo = config;
//		_dataSyncCompleted = true;
//	}

//	//get data fail callback
//	void DownloadDataFail(DataInfo config, string context, string filename, int code)
//	{
//		Logger.Error("Download Data failed, filename " + filename);
//		//restart get data
////		StartCoroutine(DownloadDataFromServer(config, context, DownloadDataSuccess, DownloadDataFail));
//		HandleUpdateError(AppLoadingError.DATA_UPDATE_FAILED);
//	}

//	private void HandleUpdateError(AppLoadingError errorType)
//	{
//		if  (_onProgressError != null)
//		{
//			// 尝试弹出更新失败提示
//			_onProgressError(errorType);
//		}
//		else
//		{
//			// 无法尝试，直接退回登陆
//			AppLogger.Error("[DataSync] data update failed, reboot game!!!!!!!!!");
//			GameManager.RebootGameToLaunch();
//		}
//	}

//	//get datainfo from server
//	int _datainfoIPIndex = 0;
//	IEnumerator GetDataInfoConfig(float waitTime) {
//        yield return Yielders.GetWaitForSeconds(waitTime);


//        /*				
//                if (AnnouncementManager._announcementIPAddresses != null && AnnouncementManager._announcementIPAddresses.Length > 0) 
//                {
//                    if (_datainfoIPIndex >= AnnouncementManager._announcementIPAddresses.Length)
//                        _datainfoIPIndex = 0;

//                    IPAddress ip = AnnouncementManager._announcementIPAddresses[_datainfoIPIndex];
//                    _datainfoIPIndex++;

//                    dataURL = Path.Combine(Path.Combine(Path.Combine("http://" + ip.ToString() + "/data", AppInfo.productId), AppInfo.marketVersion), dataVerUpdate.ToString()).Replace('\\', '/').TrimEnd(new char[]{'/'});

//                    // 由于更新版本上传服务器后，不会变化，所以不带v＝xxx参数（CDN回源操作）
//                    string URL = Path.Combine(dataURL, dataInfoFileName).Replace('\\', '/').TrimEnd(new char[]{'/'});
//                    Logger.Debug("retriveData from url: " + URL);
//                    StartCoroutine(TionManager.Instance.BestHttpJsonRequestWithIP(
//                        URL, 
//                        RetrieveDataVersionSuccess, 
//                        RetrieveDataVersionFail));
//                }
//                else
//        */
//        {
//            AppLogger.Debug("DataSync 解析更新地址失败，使用域名");
//			string cdnURL = AnnouncementManager.CurrentCDN;
//			dataURL = Path.Combine(Path.Combine(Path.Combine("http://" + cdnURL + "/data", AppInfo.productId), AppInfo.marketVersion), dataVerUpdate.ToString()).Replace('\\', '/').TrimEnd(new char[]{'/'});

//			string URL = Path.Combine(dataURL, dataInfoFileName).Replace('\\', '/').TrimEnd(new char[]{'/'}); 
//			AppLogger.Debug("DataSync retriveData from url: " + URL);
//			StartCoroutine(TionManager.Instance.BestHttpJsonRequestWithIP(
//				URL, 
//				RetrieveDataVersionSuccess, 
//				RetrieveDataVersionFail));
//		}
//	}

//	private float _updatedCount = 0f;
//	private float _totalUpdateCount = 0f;
//	public float UpdateProgress
//	{
//		get {
//			if (_totalUpdateCount <= 0f)
//			{
//				return 0f;
//			}
//			var progress = _updatedCount / _totalUpdateCount;
//			if (progress > 1f)
//			{
//				progress = 1f;
//			}
//			return progress;
//		}
//	}


//	//下载数据！！！
//	IEnumerator DownloadDataFromServer(DataInfo info, string textInfoFile, DownloadDelegate onSuccess, DownloadDelegate onErrorHappened) {

//		// 等待拷贝数据到缓存目录
//		while(!_copySuccess)
//		{
//			yield return null;
//		}

//		bool locked = true; // lock process to wait until current file is successfully downloaded.
//		bool haserror = false;
//		int downloadFileIndex = 0; // move on to next file only if current file is successfully download, or current file will be downloaded again.
//		int retry = 0;
//		string errorFile = "";
//		int errorCode = 0;

//		List<int> indexList = new List<int>();
//		// The localDataInfo.version == -1 means the local data info is missing
//		if (localDataInfo.version == -1)
//		{
//			// 本地数据版本信息丢失，更新所有文件
//			//FIXME, 这里需要输出日之
//			for (int i = 0; i < info.fileInfos.Count; i++)
//			{
//				indexList.Add(i);
//			}
//		}
//		else
//		{
//			// 筛选需要更新的文件
//			// Find changed data files by comparing md5
//			var remoteFileCount = info.fileInfos.Count;
//			for (int i = 0; i < remoteFileCount; i++)
//			{
//				var fileRemote = info.fileInfos[i];
//				var fileLocal = localDataInfo.fileInfos.Find(local => local.file == fileRemote.file);
//				if (fileLocal == null)
//				{
//					// 新增文件
//					indexList.Add(i);
//					continue;
//				}
//				if (fileLocal.md5 != fileRemote.md5)
//				{
//					indexList.Add(i);
//					//FIXME, 这里需要输出日之
//				}
//			}
//		}

//		_totalUpdateCount = indexList.Count;

//		Logger.Debug("[DataSync] DownloadDataFromServer start");

//		Dictionary<string, byte[]> dataDic = new Dictionary<string, byte[]>();
//		int filterIndex = 0;
//		while (filterIndex < indexList.Count) {

//			downloadFileIndex = indexList[filterIndex];
//			var fileInfo = info.fileInfos[downloadFileIndex];

//			// reset flags.
//			locked = true;
//			haserror = false;	
			
//			//开始下载数据文件
//			StartCoroutine(TionManager.Instance.BestHttpDataRequestWithIP(
//				Path.Combine(dataURL, fileInfo.file).Replace('\\', '/').TrimEnd(new char[]{'/'}), 
				
//				//succ callback
//				(byte []data) => {
//				// check completation.
//				if(CheckMD5(data, fileInfo.md5)) {
//					string fileName = fileInfo.file;
//					if (!dataDic.ContainsKey(fileName))
//					{
//						dataDic.Add(fileName, data);
//					}
//					else
//					{
//						// should not happen
//						//FIXME, 需要日止
//						dataDic[fileName] = data;
//					}
//					++filterIndex;
//					_updatedCount = filterIndex;
//				}
//				else {
//					// MD5 fail, this file is not correct, need re-download it.
//					++retry;
//					haserror = true;
//					errorCode = 40;
//					errorFile = fileInfo.file;
//					Logger.Error("[DataSync] DownloadDataFromServer get file fail by MD5 " + errorFile);
//				}
//				// unlock the cycle to move on to next file.
//				locked = false;
//				},
				
//				//fail callback
//				(int errorcode,string exception, string stackTrace) => {
//					//FIXME, 需要日止
//					// failed to download, unlock the cycle but not increase downloadFileIndex, it makes the file be download again.
//					++retry;
//					locked = false;
//					haserror = true;
//					errorCode = errorcode;
//					errorFile = fileInfo.file;
//					Logger.Error("[DataSync] DownloadDataFromServer get file fail " + errorFile);
//			}
//			));
//			// once 1 file is downloaded successfully, unlock this cycle, next file may start to be downloaded.
//			while(locked) {
//				yield return null;
//			}
//			// retry count detect.
//			if(haserror) {
//				if(retry < 5) {
//					//没有到失败次数,重新下载上次的文件
//                    yield return Yielders.GetWaitForSeconds(0.1f);

//                    Logger.Error("[DataSync] DownloadDataFromServer retry " + errorFile);
//				}
//				else {
//					// error callback here.
//					//失败次数过多了
//					if(onErrorHappened != null) {
//						Logger.Error("[DataSync] DownloadDataFromServer fail callback");
//						onErrorHappened(info, textInfoFile, errorFile, errorCode);
//					}
//					yield break;
//				}
//			}
//		}

		
//		// save data to file.
//		foreach (var dataPair in dataDic)
//		{
//			string fileName = dataPair.Key;
//			byte[] data = dataPair.Value;
//			try
//			{
//				File.WriteAllBytes(Path.Combine(info.path, fileName).Replace('\\', '/').TrimEnd(new char[]{'/'}), data);
//			}
//			catch (Exception ex)
//			{
//				Logger.Error("[DataSync] DownloadDataFromServer write to file error, stack trace: " + ex.StackTrace);
//				HandleUpdateError(AppLoadingError.DISK_FULL);
//				yield break;
//			}
//			Logger.Debug("[DataSync] DownloadDataFromServer write file OK " + fileName);
//		}

//		try
//		{
//			// all data files are downloaded, write the data info file (dataInfo.json).
//			File.WriteAllText(Path.Combine(info.path, dataInfoFileName).Replace('\\', '/').TrimEnd(new char[]{'/'}), textInfoFile);

//			// save current dataupload
//			PlayerPrefs.SetInt(DataUploadKey, dataVerUpdate);
//			PlayerPrefs.Save();
//		}
//		catch (Exception ex)
//		{
//			Logger.Error(ex.StackTrace);
//			HandleUpdateError(AppLoadingError.DISK_FULL);
//			yield break;
//		}

//		if(onSuccess != null) {
//			Logger.Debug("[DataSync] DownloadDataFromServer succ callback");
//			onSuccess(info, textInfoFile, "", 0);
//		}
//	}

//#endregion 

    private DataInfo GetDataInfo(Hashtable table, string path, DataInfo ret) {
		ret.version = System.Convert.ToInt32(table["version"]);
		ret.path = path;
		ArrayList fileList = (ArrayList)table["dataFiles"];
		ret.fileInfos = new List<FileInfo>(fileList.Count);
		for(int i = 0;i < fileList.Count;++i) {
			Hashtable elem = (Hashtable)fileList[i];
			FileInfo info = new FileInfo();
			info.file = System.Convert.ToString(elem["file"]);
			info.md5 = System.Convert.ToString(elem["md5"]);
			ret.fileInfos.Add(info);
		}
		return ret;
	}

	private bool CheckMD5(byte []bytes, string md5)
	{
		System.Security.Cryptography.MD5CryptoServiceProvider md5Service = new System.Security.Cryptography.MD5CryptoServiceProvider();
		byte []hash = md5Service.ComputeHash(bytes);
		int []strmask = new int[]{48, 87};
		if(md5.Length == hash.Length * 2) {
			for(int i = 0;i < hash.Length;++i) {
				int h = ((hash[i] >> 4) & 0xf), l = (hash[i] & 0xf);
				h += strmask[h / 10];
				l += strmask[l / 10];
				if(md5[i * 2] != h || md5[i * 2 + 1] != l) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	

	
	
	public class DataBytes {
		public byte []bytes;
		public bool loadByWWW;
	}

	public delegate void DeserializeCallback();
	public IEnumerator DeserializeDataFile(DeserializeCallback callback)
	{
		// 数据加载开始
		//TionManager.Instance.LoadingMsg("LoadDataStart", (long)Time.realtimeSinceStartup); // 数据加载开始

		_dataLoaded = 0;
		yield return StartCoroutine(ReadProtobuf());
		_dataLoaded = _dataFileToLoad; // to ensure process won't go into dead end.

		// 数据加载结束
		//TionManager.Instance.LoadingMsg("LoadDataEnd", (long)Time.realtimeSinceStartup); // 数据加载开始

		if(callback != null) {
			callback();
		}
	}

	public System.Collections.Generic.Dictionary<System.Type, object> GetDeserializedData()
	{
		return _dataAfterDeserialized;
	}
	public void ClearTempData()
	{
		//AppLogger.Debug("DataSync Clear datas");
		_dataAfterDeserialized.Clear();
	}

	public IEnumerator GetDataBytes(string name, DataBytes result)
	{
		// localDataInfo.version >= 0 说明缓存目录已有一份数据
		string directory = ((localDataInfo != null && localDataInfo.version >= 0) ? localDataInfo.path : dataInfoFileDirectoryInStreamingAssets);
		string path = Path.Combine(directory, name).Replace('\\', '/').TrimEnd(new char[]{'/'});

		//Logger.Debug ("Loading data file from path " + path);
        Debug.Log( "Loading data file from path " + path );
        if(path.Contains("file://")) {
			result.loadByWWW = true;
			using(WWW www = new WWW(path)) {
				yield return www;
				if(string.IsNullOrEmpty(www.error)) {
					//Logger.Debug("found by WWW");
                    Debug.Log( "found by WWW" );
                    byte []bytes = www.bytes;
					result.bytes = new byte[bytes.Length];
					Buffer.BlockCopy(bytes, 0, result.bytes, 0, bytes.Length);
				}
				www.Dispose();
			}
		}
		else {
			if(File.Exists(path)) {
				//Logger.Debug("found");
                Debug.Log( "found" );
                result.loadByWWW = false;
				FileStream fs = File.OpenRead(path);
				result.bytes = new byte[fs.Length];
				fs.Read(result.bytes, 0, (int)fs.Length);
				fs.Close();
			}
		}
	}
    void OnGUI()
    {
        if( GUI.Button( new Rect( 0, 0, 100, 100 ), "ReadData" ) )
        {
            StartCoroutine( ReadProtobuf() );
        }
    }
	private IEnumerator ReadProtobuf()
	{
		//Logger.Debug("[RCD] ReadProtobuf start");
	
		#if LOADING_STATICS
		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] ReadProtobuf start", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
		#endif
	
		yield return StartCoroutine(ReadDataFile<ProtobufGen.Item_ARRAY>("item.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ATTRIBUTES_ARRAY>("attributes.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LEVELATTRIBUTES_ARRAY>("levelattributes.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SKILLLIST_ARRAY>("skilllist.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SKILLUPGRADE_ARRAY>("skillupgrade.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GENERALSKILL_ARRAY>("generalskill.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ACDATA_ARRAY>("acdata.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DIALOGUE_INFO_ARRAY>("dialogue_info.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DIALOGUE_TRIGGER_ARRAY>("dialogue_trigger.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SCENTENCE_ARRAY>("scentence.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EVOLUTION_ARRAY>("evolution.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MATERIALENHANCE_ARRAY>("materialenhance.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LEVEL_INFO_ARRAY>("level_info.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ITEMBUFF_ARRAY>("itembuff.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EQUIPRESOLVE_ARRAY>("equipresolve.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CORPLEVEL_ARRAY>("corplevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FORMULA_ARRAY>("formula.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EUIPTRICKDETAIL_ARRAY>("euiptrickdetail.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EUIPTRICKSETTINGS_ARRAY>("euiptricksettings.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MULTIHIT_ARRAY>("multihit.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CONFIG_ARRAY>("config.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.Quest_ARRAY>("quest.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.MONTHLYGIFT_ARRAY>("monthlygift.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.MONTHLYACTIVITY_ARRAY>("monthlyactivity.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CHAPTERAWARD_ARRAY>("chapteraward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NPCDISPLAY_ARRAY>("npcdisplay.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MAINNPC_ARRAY>("mainnpc.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GACHASETTINGS_ARRAY>("gachasettings.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ATTRIBUTESGS_ARRAY>("attributesgs.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.AROUSAL_ARRAY>("arousal.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWGENERAL_ARRAY> ("newgeneral.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GENERALSTART_ARRAY> ("generalstart.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GENERALRELATION_ARRAY>("generalrelation.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.RELATIONLEVEL_ARRAY>("relationlevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NGQDETAIL_ARRAY>("ngqdetail.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NGQSETTINGS_ARRAY>("ngqsettings.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.VIPSETTINGS_ARRAY>("vipsettings.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BOSSFIGHTRANKING_ARRAY> ("bossfightranking.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GOLDLEVEL_ARRAY>("goldlevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EXPLEVEL_ARRAY>("explevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DCLEVEL_ARRAY>("dclevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MODECONTROL_ARRAY>("modecontrol.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PRIVILEGE_ARRAY>("privilege.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DAILYGIFT_ARRAY>("dailygift.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SECTION_ARRAY>("section.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.STORY_ARRAY>("story.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ROLLINFO_ARRAY>("rollinfo.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CONDITION_ARRAY>("condition.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DISPLAY_ARRAY>("display.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CONDITIONROLE_ARRAY>("conditionrole.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LOADINGTIP_ARRAY>("loadingtip.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.COMBAT_REPORT_ARRAY>("combat_report.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FTE_ARRAY>("fte.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FTEDIALOGUE_ARRAY>("ftedialogue.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NONCOMPULSORYFTE_ARRAY>("noncompulsoryfte.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.STARLVUP1_ARRAY>("starlvup1.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BLESSITEM_ARRAY>("blessitem.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ZHHANS_ARRAY>("zhhans.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPRANKREWARD_ARRAY>("bscpvprankreward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPSWTCOST_ARRAY>("bscpvpswtcost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CREDITLIST_ARRAY>("creditlist.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWGSCONTROL_ARRAY>("newgscontrol.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.IAPMAIN_ARRAY>("iapmain.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.IAPBASE_ARRAY>("iapbase.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LEVEL_CONDITION_ARRAY>("level_condition.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NPCUI_ARRAY>("npcui.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PLAYERGROWTHREF_ARRAY>("playergrowthref.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.CONDITIONPAGE_ARRAY>("conditionpage.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MAILMAIN_ARRAY>("mailmain.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.COMIC_ARRAY>("comic.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SUBTITLEGROUP_ARRAY>("subtitlegroup.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BOSSFIGHT_ARRAY>("bossfight.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SHOPGOODS_ARRAY>("shopgoods.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SHOPDISPLAY_ARRAY>("shopdisplay.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PRACTICEDISPLAY_ARRAY>("practicedisplay.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SKILLPRACTICE_ARRAY>("skillpractice.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.JADEXP_ARRAY>("jadexp.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DESTINYGENERALUNLOCK_ARRAY>("destinygeneralunlock.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DESTINYGENERALSKILL_ARRAY>("destinygeneralskill.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDPOSITION_ARRAY>("guildposition.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GECONFIG_ARRAY>("geconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GEENEMYGROUP_ARRAY>("geenemygroup.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GEENEMY_ARRAY>("geenemy.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GEMODEL_ARRAY>("gemodel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GELOOT_ARRAY>("geloot.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GEGIFT_ARRAY>("gegift.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ALLREFRESHTIME_ARRAY>("allrefreshtime.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LEVEL_TRIAL_ARRAY>("level_trial.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDNUMBERS_ARRAY>("guildnumbers.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDSIGN_ARRAY>("guildsign.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LATERACCESSLOADING_ARRAY>("lateraccessloading.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.SPCIALACTIVITY_ARRAY>("spcialactivity.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FISHINGCOST_ARRAY>("fishingcost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FISHINGREWARD_ARRAY>("fishingreward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GAME_ARRAY >("game.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.RANKAWARD_ARRAY>("rankaward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FIGHTAWARD_ARRAY>("fightaward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDRANK_ARRAY>("guildrank.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDLEAD_ARRAY>("guildlead.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DAYRANK_ARRAY>("dayrank.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GANKCONFIG_ARRAY>("gankconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GANKIDS_ARRAY>("gankids.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DAILYAWARD_ARRAY>("dailyaward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ACTIVITYSHOP_ARRAY>("activityshop.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ACTIVITYQUEST_ARRAY>("activityquest.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVECONFIG_ARRAY>("gveconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVELOOT_ARRAY>("gveloot.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWSTARLVUPSETTINGS_ARRAY>("newstarlvupsettings.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWSTARLVUP_ARRAY>("newstarlvup.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWSTARLVUPSTAGECOST_ARRAY>("newstarlvupstagecost.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.JADECONDITON_ARRAY>("jadeconditon.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TPVPFPASS_ARRAY>("tpvpfpass.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TPVPREFRESH_ARRAY>("tpvprefresh.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TPVPWINREWARD_ARRAY>("tpvpwinreward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HERO_ARRAY>("hero.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROCONFIG_ARRAY>("heroconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROSTAR_ARRAY>("herostar.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FIRSTPAY_ARRAY>("firstpay.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.REBATECOST_ARRAY>("rebatecost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.IDENTITY_ARRAY>("identity.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.COUNTERSKILL_ARRAY>("counterskill.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PASSIVESKILL_ARRAY>("passiveskill.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.COINORIGIN_ARRAY>("coinorigin.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.ORIGINSHOW_ARRAY>("originshow.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GACHASHOW_ARRAY>("gachashow.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DUBBLERAWARD_ARRAY>("dubbleraward.data"));
     	yield return StartCoroutine(ReadDataFile<ProtobufGen.WBSSCORELEVEL_ARRAY>("wbsscorelevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WBSSETTINGS_ARRAY>("wbssettings.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WBSTOTALGS_ARRAY>("wbstotalgs.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPSECTOR_ARRAY>("bscpvpsector.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.TITLELIST_ARRAY>("titlelist.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BETTEREQUIP_ARRAY>("betterequip.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GROWFUND_ARRAY>("growfund.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDBAG_ARRAY>("guildbag.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDBOSS_ARRAY>("guildboss.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GBCONFIG_ARRAY>("gbconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GBENEMYGROUP_ARRAY>("gbenemygroup.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GBDROPLIST_ARRAY>("gbdroplist.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.POPUPWINDOW_ARRAY>("popupwindow.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.LEVELGIFTPURCHASE_ARRAY>("levelgiftpurchase.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.TPVPSECTOR_ARRAY>("tpvpsector.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FENGHUOMAIN_ARRAY>("fenghuomain.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FENGHUOCONFIG_ARRAY>("fenghuoconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FENGHUOLOOTSHOW_ARRAY>("fenghuolootshow.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.REVIVECOST_ARRAY>("revivecost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GEBUFF_ARRAY>("gebuff.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HOTACTIVITYIDS_ARRAY>("hotactivityids.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.DESTINYCONFIG_ARRAY>("destinyconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.NEWDESTINYGENERALLEVEL_ARRAY>("newdestinygenerallevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDACTIVITY_ARRAY>("guildactivity.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTMAIN_ARRAY>("gstmain.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTMEMBERCAP_ARRAY>("gstmembercap.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTGBOSSFIGHTBONUS_ARRAY>("gstgbossfightbonus.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTDAILYTASKEXP_ARRAY>("gstdailytaskexp.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTGOLDBONUS_ARRAY>("gstgoldbonus.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTGATEENEMYBONUS_ARRAY>("gstgateenemybonus.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTWANNAHERO_ARRAY>("gstwannahero.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GSTCONFIG_ARRAY>("gstconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.ACTIVITYCONFIG_ARRAY>("activityconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.ACTIVITYGIFT_ARRAY>("activitygift.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.RESETCOST_ARRAY>("resetcost.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.DIALOGUEIDS_ARRAY>("dialogueids.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROTALENT_ARRAY>("herotalent.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROTALENTLEVEL_ARRAY>("herotalentlevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HTPOINTPURCHASE_ARRAY>("htpointpurchase.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROSOULLEVEL_ARRAY>("herosoullevel.data")); 		
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROLEVELITEM_ARRAY>("herolevelitem.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROLEVEL_ARRAY>("herolevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.EATBAOZI_ARRAY>("eatbaozi.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPWINREWARD_ARRAY>("bscpvpwinreward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TRIGGERSKILL_ARRAY>("triggerskill.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPREWARDWEEK_ARRAY>("bscpvprewardweek.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.BSCPVPCONFIG_ARRAY>("bscpvpconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.SCLSHARE_ARRAY>("sclshare.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.SKILLLISTSORT_ARRAY>("skilllistsort.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROWINGLEVEL_ARRAY>("herowinglevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROWINGSTAR_ARRAY>("herowingstar.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EXPEDITIONLEVEL_ARRAY>("expeditionlevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.EXPEDITIONCONFIG_ARRAY>("expeditionconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROWINGLIST_ARRAY>("herowinglist.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HEROWINGTABLE_ARRAY>("herowingtable.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MONEYGOD_ARRAY>("moneygod.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.PASSAWARD_ARRAY>("passaward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.EXPEDITIONREWARD_ARRAY>("expeditionreward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGCONFIG_ARRAY>("gvgconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGHOTDATA_ARRAY>("gvghotdata.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGCITY_ARRAY>("gvgcity.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGACITYGIFT_ARRAY>("gvgacitygift.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGGUILDGIFT_ARRAY>("gvgguildgift.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGDAILYGIFT_ARRAY>("gvgdailygift.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GVGPOINTGIFT_ARRAY>("gvgpointgift.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.RELATIONSHOW_ARRAY>("relationshow.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.RELATIONACTIVE_ARRAY>("relationactive.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.RELATIONEVOLUTION_ARRAY>("relationevolution.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDCONFIG_ARRAY>("guildconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HOTACTIVITYHERO_ARRAY>("hotactivityhero.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBCONFIG_ARRAY>("fbconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBSHOP_ARRAY>("fbshop.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBBUYCOUNT_ARRAY>("fbbuycount.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBENEMY_ARRAY>("fbenemy.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBMODEL_ARRAY>("fbmodel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FRIENDCHEAT_ARRAY>("friendcheat.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FBLEVEL_ARRAY>("fblevel.data"));
		//yield return StartCoroutine(ReadDataFile<ProtobufGen.REDPACKET_ARRAY>("redpacket.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.RENAMECOST_ARRAY>("renamecost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDRENAMECHASE_ARRAY>("guildrenamechase.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GLORYWEAPONLIST_ARRAY>("gloryweaponlist.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GLORYWEAPON_ARRAY>("gloryweapon.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.INITIALIZEFASHION_ARRAY>("initializefashion.data"));		
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPSKILL_ARRAY>("hdpskill.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPENEMY_ARRAY>("hdpenemy.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPMODEL_ARRAY>("hdpmodel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPLEVEL_ARRAY>("hdplevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPREWARD_ARRAY>("hdpreward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HPDTU_ARRAY>("hpdtu.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDWORSHIPBOX_ARRAY>("guildworshipbox.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.GUILDWORSHIPCOST_ARRAY>("guildworshipcost.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WSPVPMAIN_ARRAY>("wspvpmain.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WSPVPFPASS_ARRAY>("wspvpfpass.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WSPVPSECTOR_ARRAY>("wspvpsector.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WSBOXREWARD_ARRAY>("wsboxreward.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WSPVPREFRESH_ARRAY>("wspvprefresh.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPLEVELSECTION_ARRAY>("hdplevelsection.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPREWARDLIST_ARRAY>("hdprewardlist.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.FATETABLE_ARRAY>("fatetable.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.FATELEVEL_ARRAY>("fatelevel.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.REFRESHCROPS_ARRAY>("refreshcrops.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.CROPSGIFT_ARRAY>("cropsgift.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.GIFTLOOT_ARRAY>("giftloot.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.RCCONFIG_ARRAY>("rcconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.HDPCONFIG_ARRAY>("hdpconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.LOSTGOODSHOP_ARRAY>("lostgoodshop.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.AUGUR_ARRAY>("augur.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STARMAP_ARRAY>("starmap.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STARMAPCONFIG_ARRAY>("starmapconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STARSOUL_ARRAY>("starsoul.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STARSOULUPGRADE_ARRAY>("starsoulupgrade.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.REFRESHPRICE_ARRAY>("refreshprice.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STOREBLANK_ARRAY>("storeblank.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STOREGROUP_ARRAY>("storegroup.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.REFRESHTIME_ARRAY>("refreshtime.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.STARSOULTYPE_ARRAY>("starsoultype.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.ITEMGROUP_ARRAY>("itemgroup.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WBOSSENEMY_ARRAY>("wbossenemy.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.WBOSSDATA_ARRAY>("wbossdata.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WBOSSLEVEL_ARRAY>("wbosslevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WBDEMAGEREWARD_ARRAY>("wbdemagereward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WBRANKREWARD_ARRAY>("wbrankreward.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.WBOSSCONFIG_ARRAY>("wbossconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.RECOVERRESOURCES_ARRAY>("recoverresources.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.SHOPSETTING_ARRAY>("shopsetting.data"));

		yield return StartCoroutine(ReadDataFile<ProtobufGen.MAGICPETINFO_ARRAY> ("magicpetinfo.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.MAGICPETCONFIG_ARRAY>("magicpetconfig.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PETLEVEL_ARRAY>("petlevel.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PETSTAR_ARRAY> ("petstar.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PETAPTITUDE_ARRAY> ("petaptitude.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.APTITUDEGRADE_ARRAY> ("aptitudegrade.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.PETPOSITION_ARRAY>("petposition.data"));


        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSCONFIG_ARRAY>("tbossconfig.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSDUNGEON_ARRAY>("tbossdungeon.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSENEMY_ARRAY>("tbossenemy.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSHEROTYPE_ARRAY>("tbossherotype.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSMAINDATA_ARRAY>("tbossmaindata.data"));
        yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSLOADING_ARRAY>("tbossloading.data"));
		yield return StartCoroutine(ReadDataFile<ProtobufGen.TBOSSBOXDATA_ARRAY>("tbossboxdata.data"));

		yield return StartCoroutine(ReadDataFile<ProtobufGen.BATTLEARMY_ARRAY>("battlearmy.data"));  
		yield return StartCoroutine(ReadDataFile<ProtobufGen.BATTLEARMYLEVEL_ARRAY>("battlearmylevel.data"));  

#if LOADING_STATICS
		AppLogger.Error("[LOADING STATICS] [{0}] [{1}] ReadProtobuf end", Time.realtimeSinceStartup.ToString(), AppLoading.Instance._progressBar.value.ToString());
#endif

       // Logger.Debug("[RCD] ReadProtobuf end");
		
		// if you want to add file to load here, remember to update the var below
		//     |
		//     |
		//   \ | /
		//    \|/
	}

	//|||||||      |||||||||||||||||||||||
	//||||||||    ||||||||||||||||||||||||
	//|||||||||  |||||||||||||||||||||||||
	private int _dataFileToLoad = 265;//||
	//||||||||||||||||||||||||||||||||||||
	//||||||||||||||||||||||||||||||||||||


	public float progress {
		get { 
			return _dataLoaded / (float)_dataFileToLoad;
		}
	}

	public void ResetLoadedCount()
	{
		_dataLoaded = 0;
	}

	// reference from DataManager.
	private IEnumerator ReadDataFile<T>(string dataname)
	{
		//Logger.Debug("[RCD] ReadDataFile " + dataname);
	    Debug.Log( "[RCD] ReadDataFile " + dataname );

        System.Type type = typeof(T);
		if(!_dataAfterDeserialized.ContainsKey(type)) {
			DataSync.DataBytes dataBytes = new DataSync.DataBytes();
			yield return StartCoroutine(DataSync.Instance.GetDataBytes(dataname, dataBytes));
			//yield return null; // give process a break to refresh window.
			if(dataBytes.bytes == null) {
				//Logger.Error("dataBytes.bytes == null, read data [Fai1]" + dataname);
                Debug.Log( "dataBytes.bytes == null, read data [Fai1]" + dataname );
            }
			else {
				using (MemoryStream stream = new MemoryStream(dataBytes.bytes, 0, dataBytes.bytes.Length, false)) {
					object obj = ProtoBuf.Serializer.Deserialize<T>(stream);
					_dataAfterDeserialized.Add(typeof(T), obj);
				}
			}
		}
		else {
			///Logger.Debug("{0} has been included in data list.", dataname);
           
        }
		++_dataLoaded;
		
		//Logger.Debug("[RCD] ReadDataFile OK " + dataname);
	}
       
}

//public class VerInfoLogger : LoggerSingleton<VerInfoLogger>
//{
//	public VerInfoLogger()
//	{
//		SetLoggerName("VersionInfo");
//	}
//}
